import os
import configparser  # 解析ini文件
import json  # 解析json
import re  # 正则
import psutil  # 获取硬件信息

from app.config import file_threat_rules_json, user_defined_rules_active  # 引入规则文件和自定义规则
from app.models.mongo_model import mongo_conn  # mongodb
from app.models.redis_model import redis_conn  # redis
from app.threat_rules.threats import *
from app.tools.common import config_comm, torjan_crontab_info, used_cpu_high, change_corn_default


class Monitor:
    # 将ip和ua写入到redis
    def get_ip_ua_to_redis(self, ip, ua):
        rc = redis_conn()  # 与redis建立连接
        # 检查ip是否已经存在redis中
        if rc.get(ip):
            frequently_accessed(ip, ua)
        else:
            rc.setex(ip, 10, ua)  # 10秒后过期

    # 处理url路径(path)是否存在问题
    def get_ip_path(self, ip, ua, path):
        # 读取json规则文件
        with open(file_threat_rules_json) as t_rs:
            t_r = json.load(t_rs)
        rule_comm = t_r['threat_rule']
        sql_info = rule_comm['sql_inject']
        sql_details = sql_info['details']
        sql_lv = sql_info['Level']
        xss_info = rule_comm['xss_attack']
        xss_details = xss_info['details']
        xss_lv = xss_info['Level']
        s_i = sql_info['words']  # 获取sql注入关键词
        for si in s_i:
            if si in path:
                print(f"sql敏感词：{si}")
                web_attack(sql_details, ip, ua, sql_lv, path)
        # xss攻击
        if 'javascript' in path:
            web_attack(xss_details, ip, ua, xss_lv, path)
        # 如果开启了自定义规则，就执行
        if user_defined_rules_active:
            title = ['sql_inject', 'xss_attack']
            details = ['sql注入', 'xss攻击']
            for i in range(len(title)):
                pub_data = self.user_defined_rule(title[i], details[i])
                if pub_data:
                    lv = pub_data[title[i]]['Level']  # 获取程度
                    words = pub_data[title[i]]['words']  # 获取关键词
                    for word in words:
                        if word in path:
                            web_attack(details[i], ip, ua, lv, path)

    # php.ini安全检查
    def get_php_ini(self, path, funcs):
        config = configparser.ConfigParser()  # 创建对象
        config.read(path)  # 读配置文件
        # 取相应函数的值
        for i in funcs:
            ini_val = config.get("PHP", i)
            if ini_val == "On":
                config_comm("php.ini安全检查", "信息", i, "On", "建议关闭")
            else:
                print(f"配置项 {i} 处于关闭状态，安全！本次内容不计入数据库")

    # 使用用户自定义规则进行检查
    def user_defined_rule(self, title, details):
        mon = mongo_conn()  # 连接mongodb
        collection = mon['custom']  # 指定集合
        # 获取数据
        col = collection.find_one({f'{title}.details': f'{details}'}, {'_id': 0})
        return col

    # 系统配置项检查（sshd）
    def get_sshd_conf(self, path, para):
        with open(path) as f:
            lines = f.readlines()
        for line in lines:
            for p in para:
                if re.match(f'^{p}', line):
                    config_comm("sshd_config配置文件安全检查", "信息", p, suggest="建议修改默认项")

    # 检查文件是否是木马  /opt/docker_nginx_php/www
    def check_trojan(self, feature_info):
        # 打开木马规则文件
        with open(feature_info) as trojan:
            feature = json.load(trojan)
        # 输入目录绝对路径
        directory = input("请输入目录的绝对路径：")
        files = os.listdir(directory)  # 获取目录下的所有文件列表
        for file in files:
            with open(f"{directory}/{file}") as f:
                text = f.read()
            if 'php' in text:
                for words in feature['php']:
                    if words in text:
                        torjan_crontab_info("木马文件检测", "严重", words, f"{directory}/{file}")

    # 检测系统执行计划指令
    def check_crontab(self, path):
        # 打开crontab规则文件
        with open(path) as crontab:
            feature = json.load(crontab)
        details = feature['crontab']['details']  # 获取描述
        lv = feature['crontab']['Level']  # 获取程度
        path = feature['crontab']['path']  # 路径 /var/spool/cron
        crontabs = os.listdir(path)  # 获取/var/spool/cron下的所有目录
        for crontab in crontabs:  # 遍历每一个目录
            with open(f'{path}/{crontab}') as cron:
                grammar = cron.read()
        torjan_crontab_info(details, lv, grammar, f"{path}/{crontab}")

    # 检测cpu使用率和占用最高的进程
    def cpu_data(self):
        percent_avg = psutil.cpu_percent(interval=1)  # 获取cpu平均使用率
        print(f"目前cpu的使用率为：{percent_avg}%")
        if percent_avg > 0.5:
            high = os.popen('ps aux|head -1;ps aux|grep -v PID|sort -rn -k +3|head -1').read()  # 查看占用cpu最高的程序
            high_list = high.split()
            user = high_list[11]
            pid = high_list[12]
            cpu = high_list[13]
            men = high_list[14]
            command = f"{high_list[-3]} {high_list[-2]} {high_list[-1]}"
            used_cpu_high(user, pid, cpu, men, command)

    # 检测CronJob防止提权
    def check_cron_jobs_defaule(self, path):
        # 打开crontab规则文件
        with open(path) as cron:
            content = json.load(cron)
        details = content['cron_jobs']['details']  # 获取描述
        lv = content['cron_jobs']['Level']  # 获取程度
        path = content['cron_jobs']['path']  # 路径 /etc/crontab
        lines = content['cron_jobs']['default_lines']  # 默认行数 15
        words = content['cron_jobs']['default_words']  # 默认字数 84
        default_lines = (os.popen(f'cat {path} | wc -l').read()).strip()  # 获取行数
        default_words = (os.popen(f'cat {path} | wc -w').read()).strip()  # 获取字数
        if default_lines != lines and default_words != words:
            change_corn_default(details, lv, path, lines, words)
        else:
            print(f"行数、字数未发生变化，未检测到{path}存在异常，建议人工确认。本次警告不记入数据库")
